package com.zhou.project.configurations.security.fifter;

import com.zhou.project.components.redis.RedisComponent;
import com.zhou.project.configurations.security.jwt.JwtWebToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.Max;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

public class CertificationFilter extends BasicAuthenticationFilter {

    private JwtWebToken jwtWebToken;
    private RedisComponent redisComponent;

    //时间总和
    public long sumTime=600;
    //最大时间
    public long MaxTime=7*3600;
    //基础时间
    public long baseTime=600;
    //频繁使用软件次数
    public int frequentlyCount=0;
    //间歇性使用软件次数
    public int missionCount=0;


    public CertificationFilter(AuthenticationManager authenticationManager, JwtWebToken jwtWebToken, RedisComponent redisComponent) {
        super(authenticationManager);
        this.jwtWebToken = jwtWebToken;
        this.redisComponent = redisComponent;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //获取有没有携带token
        String authorization = request.getHeader(jwtWebToken.getHeader());
        //客户端携带token符合规则
        if(StringUtils.hasLength(authorization) && authorization.startsWith(jwtWebToken.getPrefix()))
        {
            //截取获取token
            String token= authorization.substring(jwtWebToken.getPrefix().length());

            //判断该请求是否通过认证
            Map<Object,Object> hash = redisComponent.hmget(token);
//            String username=(String) redisComponent.get(token);
            if (!ObjectUtils.isEmpty(hash.get("username")))
            {

                Collection<SimpleGrantedAuthority> authoritiesList = new ArrayList<>();
                //1.通过spring security 该请求通过认证
                //2.通过token获取用户权限列表
                List<String> authorities=(List<String>)hash.get("authorities");
                //3.封装用户权限列表
                authorities.forEach((code->{
                    authoritiesList.add(new SimpleGrantedAuthority(code));
                }));

                //创建认证对象 账号 权限集合
                UsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(hash.get("username"),null,authoritiesList);
                //通知Spring Security 认证对象
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);

                //4. 根据登录相关参数精选续约
                //开始：600m
                //剩余：10m 过期 10m 600 +10
                //剩余：590m 10m 600+590
                //阀值：取所有用户的平局数值 续约时间降低倍

                //1.获得剩余时间 如果剩余时间<1分钟 它直接获得一个600秒的时间   >1分钟才进行算法计算
                //2.如果这一次的时间与上一次的时间间隔 小于10m 时间 频繁使用次数+1 间歇性如果为0不变,不为0--  时间+sumTime一半 直到加到最大
                //3.如果这一次的时间与上一次的时间间隔 大于300m 时间 频繁使用次数-1,间歇性次数++ 时间-sumTime一半 直到减到基础值
                //4.每次都要比较频繁使用次数大小，并确定是时间是增加还是减少
                Long nowTime=redisComponent.getExpire(token);
                System.out.println("sumTime:"+sumTime);
                System.out.println("nowTime:"+nowTime);
                //如果当前时间小于最大时间的一半才进行时间的计算
                if (nowTime>60) {
                    if (sumTime-nowTime<10) {
                        //小10m 时间加sumTime的一半 直到+到最大值 频繁使用次数+1 间歇性如果为0不变,不为0--
                        frequentlyCount++;
                        if (frequentlyCount>=missionCount)
                        {
                            sumTime += sumTime / 2;
                            //如果sumTime大于了最大时间 直接按最大时间计算
                            if (sumTime>MaxTime){
                            redisComponent.expire(token,MaxTime);
                            }
                            //如果missionCount不为0 进行--
                            if (missionCount!=0)
                                missionCount--;
                        }else {
                          //如果frequentlyCount<missionCount
                            sumTime+=baseTime;
                            if (sumTime>MaxTime){
                                redisComponent.expire(token,MaxTime);
                            }
                        }
                    }else if (10<=sumTime-nowTime && sumTime-nowTime<sumTime/2){
                        //大于10m 小于sumTime的一半  总时间加600m 其他不变 直到+到最大值
                        sumTime+=baseTime;
                        //如果sumTime大于了最大时间 直接按最大时间计算
                            if (sumTime>MaxTime){
                                redisComponent.expire(token,MaxTime);
                            }
                        } else {
                        //操作时间大于sumTime的一半 总时间-sumTime的一半 （不能小于1分钟 小于宜分治直接给600m）
                        // 频繁使用次数-1,间歇性次数++
                        missionCount++;
                       if (frequentlyCount>=missionCount){
                           sumTime+=baseTime;
                               if (sumTime>MaxTime){
                                   redisComponent.expire(token,MaxTime);
                               }
                               if (frequentlyCount!=0){
                                   frequentlyCount--;
                               }
                       }else {
                           sumTime-=sumTime/2;
                           if (sumTime<=60){
                               redisComponent.expire(token,baseTime);
                           }
                       }
                        }
                }else{
                        redisComponent.expire(token,baseTime);
                    }

                    redisComponent.expire(token,sumTime);
            }


           /* boolean a= jwtWebToken.isExpiration(token);
            System.out.println("a = " + a);*/
        }
        super.doFilterInternal(request, response, chain);
    }
}



